// AAAA. 作用域
//  1. 全局作用域
//  2. 函数作用域（局部作用域）
//  3. 块级作用域 {}

// 1. 全局作用域：任何不在函数中或是大括号中声明的变量，都是在全局作用域下（全局作用域下声明的变量可以在程序的任意位置访问）
var greeting = 'Hello World!';   // 全局变量
function greet() {
  console.log(greeting);
}

greet();  // 'Hello World!'


// 2. 函数作用域（局部作用域）：如果一个变量是在函数内部声明的它就在一个函数作用域下面（这些变量只能在函数内部访问，不能在函数以外去访问）
function greet() {
    var greeting = 'Hello World!';
    console.log(greeting);
  }
  
  greet(); // 'Hello World!'
  console.log(greeting); // Uncaught ReferenceError: greeting is not defined


// 3. 块级作用域：在大括号中使用let和const声明的变量存在于块级作用域中（在大括号之外不能访问这些变量）
{
    // 块级作用域中的变量
    let greeting = 'Hello World!';
    var lang = 'English';
    console.log(greeting); // 'Hello World!'
  }
  console.log(lang);  // 变量 'English'
  console.log(greeting); // 报错：Uncaught ReferenceError: greeting is not defined
  
//--------------------------------------------------------------------------------------------------------------------
// BBBB. 作用域链
// 当在Javascript中使用一个变量的时候，首先Javascript引擎会尝试在当前作用域下去寻找该变量
// 如果没找到，再到它的上层作用域寻找，以此类推直到找到该变量或是已经到了全局作用域
// 如果在全局作用域里仍然找不到该变量，它就会在全局范围内隐式声明该变量(非严格模式下)或是直接报错



// CCCC. 词法作用域（Lexical Scope） ：定义表达式并能被访问的区间
// 定义一个全局作用域变量：
const myName = "Oluwatobi";

// 在函数体内调用myName变量
function getName() {
  return myName;
}

console.log(getName()) // 'Oluwatobi'

// 根据定义，词法作用域 意味着【定义时】的作用域，并不是调用时的作用域
// 因此myName变量的词法作用域是全局作用域，因为我们在全局环境下定义了myName变量


